﻿#include "myscene.h"
#include <QDebug>
#include <QDialog>
#include <QIcon>
#include <QString>
#include <QToolTip>
#include <ctime>
#include <iostream>

MyScene::MyScene(QWidget *parent) : QWidget(parent) {
    setWindowIcon(QIcon(":/pic/mine.ico"));
    initScene();
    setMouseTracking(true);
    this->setFixedSize(GRID_NUM_HOR * GRID_WIDTH,
                       GRID_NUM_VER * GRID_WIDTH + STATUSBAR_HEIGHT);
    connect(this, &MyScene::simulateLeftClickSignal, this,
            &MyScene::leftClickSlot);
    connect(this, &MyScene::simulateRightClickSignal, this,
            &MyScene::rightClickSlot);
    connect(this, &MyScene::doubleClickSignal, this, &MyScene::leftClickSlot);
    connect(this, &MyScene::boom, this, &MyScene::stopGame);
    connect(this, &MyScene::statusIconClicked, this, &MyScene::statusIconSlot);
    connect(this, &MyScene::mousePush, this, &MyScene::gridSet);
    connect(this, &MyScene::mouseMovePush, this,
            &MyScene::mouseMoveGridPushAndPop);
    connect(this, &MyScene::beginGame, this, &MyScene::forceTimer);
}

void MyScene::mousePressEvent(QMouseEvent *event) {
    if (isStop)
        return;
    if (STATUSBAR_HEIGHT < event->pos().y())
        if (event->button() == Qt::LeftButton ||
            event->button() == Qt::RightButton)
            emit mousePush(event->pos().x() / GRID_WIDTH,
                           (event->pos().y() - STATUSBAR_HEIGHT) / GRID_WIDTH);
}

void MyScene::closeEvent(QCloseEvent *event) { emit exitWin(); }

void MyScene::mouseReleaseEvent(QMouseEvent *event) {
    int leftside = GRID_NUM_HOR * GRID_WIDTH / 2 - STATUSBAR_HEIGHT / 2;
    int rightside = GRID_NUM_HOR * GRID_WIDTH / 2 + STATUSBAR_HEIGHT / 2;

    if (leftside <= event->pos().x() && event->pos().x() <= rightside) {
        if (0 <= event->pos().y() && event->pos().y() <= STATUSBAR_HEIGHT) {
            if (event->button() == Qt::LeftButton) {
                emit statusIconClicked();
            }
        }
    }

    if (isStop)
        return;

    int i = event->pos().x() / GRID_WIDTH;
    int j = (event->pos().y() - STATUSBAR_HEIGHT) / GRID_WIDTH;
    if ((0 <= event->pos().x() && event->pos().x() < this->width()) &&
        (STATUSBAR_HEIGHT < event->pos().y() &&
         event->pos().y() < this->height())) {

        if (event->buttons() == (Qt::LeftButton | Qt::RightButton)) {
            emit doubleClickSignal(i, j);
        } else if (event->button() == Qt::LeftButton) {
            emit simulateLeftClickSignal(i, j);
        } else if (event->button() == Qt::RightButton) {
            emit simulateRightClickSignal(i, j);
        }
    }
}

void MyScene::mouseMoveEvent(QMouseEvent *event) {
    if (isStop)
        return;
    int i = event->pos().x() / GRID_WIDTH;
    int j = (event->pos().y() - STATUSBAR_HEIGHT) / GRID_WIDTH;
    if ((0 <= event->pos().x() && event->pos().x() < this->width()) &&
        (STATUSBAR_HEIGHT < event->pos().y() &&
         event->pos().y() < this->height())) {

            emit mouseMovePush(i, j);

    }
}

void MyScene::wheelEvent(QWheelEvent *event) {}

void MyScene::timerEvent(QTimerEvent *event) {
    if (!isBegin)
        return;
    if (isStop)
        return;
    if (event->timerId() == id) {
        restTime--;
        setLeftNumber();
    }
    if (restTime == 0) {
        emit boom();
    }
}

void MyScene::initScene() {
    m_Timer.setInterval(GAME_RATE);
    isStop = false;
    isBegin = false;
    mineNum = MINE_NUM;
    for (int i = 0; i < GRID_NUM_HOR; ++i) {
        for (int j = 0; j < GRID_NUM_VER; ++j) {
            this->singleGrid[i][j] = new Grid;
            this->singleGrid[i][j]->resize(GRID_WIDTH, GRID_WIDTH);
            this->singleGrid[i][j]->setParent(this);
            this->singleGrid[i][j]->setPixmap(QPixmap(NOTSWEEP));
            this->singleGrid[i][j]->setScaledContents(true);
            this->singleGrid[i][j]->move(
                QPoint(i * GRID_WIDTH, j * GRID_WIDTH + STATUSBAR_HEIGHT));
            this->singleGrid[i][j]->setMouseTracking(true);
        }
    }

    int tempTimerWidth = STATUSBAR_HEIGHT * 2 / 3;

    for (int i = 0; i < 3; ++i) {
        this->leftTimer[i] = new RedTimer;
        this->leftTimer[i]->setParent(this);
        this->leftTimer[i]->resize(tempTimerWidth, STATUSBAR_HEIGHT);
        this->leftTimer[i]->setScaledContents(true);
        this->leftTimer[i]->setPixmap(QPixmap(NUM_0));
        this->leftTimer[i]->move(i * tempTimerWidth, 0);
    }

    for (int i = 0; i < 3; ++i) {
        this->rightTimer[i] = new RedTimer;
        this->rightTimer[i]->setParent(this);
        this->rightTimer[i]->resize(tempTimerWidth, STATUSBAR_HEIGHT);
        this->rightTimer[i]->setScaledContents(true);
        this->rightTimer[i]->setPixmap(QPixmap(NUM_0));
        this->rightTimer[i]->move(GRID_NUM_HOR * GRID_WIDTH -
                                      3 * tempTimerWidth + i * tempTimerWidth,
                                  0);
    }

    this->centreIcon = new StatusIcon;
    this->centreIcon->setParent(this);
    this->centreIcon->resize(STATUSBAR_HEIGHT, STATUSBAR_HEIGHT);
    this->centreIcon->setScaledContents(true);
    this->centreIcon->setPixmap(QPixmap(HAPPY));
    this->centreIcon->move(GRID_NUM_HOR * GRID_WIDTH / 2 - STATUSBAR_HEIGHT / 2,
                           0);

    int tempMineNum = 0;
    while (tempMineNum < this->mineNum) {
        int x = rand() % GRID_NUM_HOR;
        int y = rand() % GRID_NUM_VER;
        if (!this->singleGrid[x][y]->hasMine) {
            this->singleGrid[x][y]->hasMine = true;
            ++tempMineNum;
        }
    }

    int temp_X, temp_Y;
    int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
    for (int i = 0; i < GRID_NUM_HOR; ++i) {
        for (int j = 0; j < GRID_NUM_VER; ++j) {
            if (this->singleGrid[i][j]->hasMine) {
                for (int k = 0; k < 8; ++k) {
                    temp_X = i + dx[k];
                    temp_Y = j + dy[k];
                    if (0 <= temp_X && temp_X < GRID_NUM_HOR && 0 <= temp_Y &&
                        temp_Y < GRID_NUM_VER) {
                        this->singleGrid[temp_X][temp_Y]->numOfMine++;
                    }
                }
            }
        }
    }
    restTime = 1000;
    setRightNumber();
}

void MyScene::refreshScene() {
    markedNum = 0;
    setRightNumber();
    centreIcon->setPixmap(QPixmap(HAPPY));
    for (int i = 0; i < GRID_NUM_HOR; ++i) {
        for (int j = 0; j < GRID_NUM_VER; ++j) {
            this->singleGrid[i][j]->initGrid();
            this->singleGrid[i][j]->updateGrid();
        }
    }

    int tempMineNum = 0;
    while (tempMineNum < this->mineNum) {
        int x = rand() % GRID_NUM_HOR;
        int y = rand() % GRID_NUM_VER;
        if (!this->singleGrid[x][y]->hasMine) {
            this->singleGrid[x][y]->hasMine = true;
            ++tempMineNum;
        }
    }

    int temp_X, temp_Y;
    int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
    for (int i = 0; i < GRID_NUM_HOR; ++i) {
        for (int j = 0; j < GRID_NUM_VER; ++j) {
            if (this->singleGrid[i][j]->hasMine) {
                for (int k = 0; k < 8; ++k) {
                    temp_X = i + dx[k];
                    temp_Y = j + dy[k];
                    if (0 <= temp_X && temp_X < GRID_NUM_HOR && 0 <= temp_Y &&
                        temp_Y < GRID_NUM_VER) {
                        this->singleGrid[temp_X][temp_Y]->numOfMine++;
                    }
                }
            }
        }
    }

    isStop = false;
    isBegin = false;
    restTime = 999;
    setLeftNumber();
}

void MyScene::leftClickSlot(int x, int y) {
    if (this->singleGrid[x][y]->isSweeped) {
        int nx, ny;
        int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
        int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
        int tempMineNum = 0;

        for (int i = 0; i < 8; ++i) {
            nx = x + dx[i];
            ny = y + dy[i];
            if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny && ny < GRID_NUM_VER &&
                singleGrid[nx][ny]->isMarked) {
                ++tempMineNum;
            }
        }
        if (tempMineNum == this->singleGrid[x][y]->numOfMine) {
            for (int i = 0; i < 8; ++i) {
                nx = x + dx[i];
                ny = y + dy[i];
                if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny &&
                    ny < GRID_NUM_VER && !singleGrid[nx][ny]->isMarked &&
                    !singleGrid[nx][ny]->isSweeped) {
                    leftClickSlot(nx, ny);
                }
            }
        } else {
            for (int i = 0; i < 8; ++i) {
                nx = x + dx[i];
                ny = y + dy[i];
                if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny &&
                    ny < GRID_NUM_VER && !singleGrid[nx][ny]->isMarked &&
                    !singleGrid[nx][ny]->isSweeped) {
                    this->singleGrid[nx][ny]->setPixmap(QPixmap(NOTSWEEP));
                }
            }
        }

    } else if (this->singleGrid[x][y]->hasMine) {
        if (!isBegin) {
            isBegin = true;
            emit beginGame();
        }
        this->singleGrid[x][y]->isSteped = true;
        this->singleGrid[x][y]->isSweeped = true;
        this->singleGrid[x][y]->updateGrid();
        emit boom();
        return;
    } else {
        if (!isBegin) {
            isBegin = true;
            emit beginGame();
        }
        this->singleGrid[x][y]->isSweeped = true;
        this->singleGrid[x][y]->updateGrid();
    }

    if (this->singleGrid[x][y]->numOfMine != 0)
        return;

    int nx, ny;
    int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};

    for (int i = 0; i < 8; ++i) {
        nx = x + dx[i];
        ny = y + dy[i];
        if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny && ny < GRID_NUM_VER &&
            !singleGrid[nx][ny]->isSweeped) {
            leftClickSlot(nx, ny);
        }
    }
}

void MyScene::rightClickSlot(int x, int y) {
    int nx, ny;
    int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
    int tempMineNum = 0;
    if (this->singleGrid[x][y]->isSweeped) {

        for (int i = 0; i < 8; ++i) {
            nx = x + dx[i];
            ny = y + dy[i];
            if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny && ny < GRID_NUM_VER &&
                singleGrid[nx][ny]->isMarked) {
                ++tempMineNum;
            }
        }
        if (tempMineNum == this->singleGrid[x][y]->numOfMine) {
            for (int i = 0; i < 8; ++i) {
                nx = x + dx[i];
                ny = y + dy[i];
                if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny &&
                    ny < GRID_NUM_VER && !singleGrid[nx][ny]->isMarked &&
                    !singleGrid[nx][ny]->isSweeped) {
                    leftClickSlot(nx, ny);
                }
            }
        } else {
            for (int i = 0; i < 8; ++i) {
                nx = x + dx[i];
                ny = y + dy[i];
                if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny &&
                    ny < GRID_NUM_VER && !singleGrid[nx][ny]->isMarked &&
                    !singleGrid[nx][ny]->isSweeped) {
                    this->singleGrid[nx][ny]->setPixmap(QPixmap(NOTSWEEP));
                }
            }
        }
    } else {
        if (this->singleGrid[x][y]->isMarked) {
            this->singleGrid[x][y]->isMarked = false;
            markedNum--;
            setRightNumber();
        } else {
            this->singleGrid[x][y]->isMarked = true;
            markedNum++;
            setRightNumber();
        }
        this->singleGrid[x][y]->updateGrid();
    }
}

void MyScene::gridSet(int x, int y) {
    if (this->singleGrid[x][y]->isSweeped == false)
        return;
    int nx, ny;
    int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
    for (int i = 0; i < 8; ++i) {
        nx = x + dx[i];
        ny = y + dy[i];
        if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny && ny < GRID_NUM_VER &&
            !singleGrid[nx][ny]->isSweeped && !singleGrid[nx][ny]->isMarked) {
            this->singleGrid[nx][ny]->setPixmap(QPixmap(MINE_0));
        }
    }
}

void MyScene::stopGame() {
    centreIcon->setPixmap(QPixmap(UNHAPPY));
    for (int i = 0; i < GRID_NUM_HOR; ++i) {
        for (int j = 0; j < GRID_NUM_VER; ++j) {
            if (this->singleGrid[i][j]->hasMine &&
                !this->singleGrid[i][j]->isSteped) {
                this->singleGrid[i][j]->setPixmap(QPixmap(MINE));
            }
        }
    }
    restTime = 999;

    isStop = true;
}

void MyScene::statusIconSlot() { refreshScene(); }

void MyScene::mouseMoveGridPushAndPop(int x, int y) {
    if (!this->singleGrid[x][y]->isSweeped  && !this->singleGrid[x][y]->isMarked)
        this->singleGrid[x][y]->setPixmap(QPixmap(MINE_0));
    int nx, ny;
    int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};
    int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};
    for (int i = 0; i < 8; ++i) {
        nx = x + dx[i];
        ny = y + dy[i];
        if (0 <= nx && nx < GRID_NUM_HOR && 0 <= ny && ny < GRID_NUM_VER) {
            this->singleGrid[nx][ny]->updateGrid();
        }
    }
}

void MyScene::forceTimer() {
    m_Timer.start();
    connect(&m_Timer, &QTimer::timeout, [=]() { checkWin(); });
}

void MyScene::checkWin() {
    if (MINE_NUM == markedNum) {
        for (int i = 0; i < GRID_NUM_HOR; ++i) {
            for (int j = 0; j < GRID_NUM_VER; ++j) {
                if (this->singleGrid[i][j]->hasMine !=
                    this->singleGrid[i][j]->isMarked)
                    return;
            }
        }
        centreIcon->setPixmap(QPixmap(VICTORY));
        isStop = true;
    }
}

void MyScene::setRightNumber() {
    rightNum = mineNum - markedNum;
    if (rightNum >= 0) {
        int hundred, ten, one;
        hundred = rightNum / 100;
        ten = (rightNum % 100) / 10;
        one = rightNum % 10;

        setSingleNumber(hundred, rightTimer[0]);
        setSingleNumber(ten, rightTimer[1]);
        setSingleNumber(one, rightTimer[2]);
    }
}

void MyScene::setLeftNumber() {
    if (restTime >= 0) {
        int hundred, ten, one;
        hundred = restTime / 100;
        ten = (restTime % 100) / 10;
        one = restTime % 10;

        setSingleNumber(hundred, leftTimer[0]);
        setSingleNumber(ten, leftTimer[1]);
        setSingleNumber(one, leftTimer[2]);
    }
}

void MyScene::setSingleNumber(int x, RedTimer *timeNum) {
    switch (x) {
    case 0:
        timeNum->setPixmap(QPixmap(NUM_0));
        break;
    case 1:
        timeNum->setPixmap(QPixmap(NUM_1));
        break;
    case 2:
        timeNum->setPixmap(QPixmap(NUM_2));
        break;
    case 3:
        timeNum->setPixmap(QPixmap(NUM_3));
        break;
    case 4:
        timeNum->setPixmap(QPixmap(NUM_4));
        break;
    case 5:
        timeNum->setPixmap(QPixmap(NUM_5));
        break;
    case 6:
        timeNum->setPixmap(QPixmap(NUM_6));
        break;
    case 7:
        timeNum->setPixmap(QPixmap(NUM_7));
        break;
    case 8:
        timeNum->setPixmap(QPixmap(NUM_8));
        break;
    case 9:
        timeNum->setPixmap(QPixmap(NUM_9));
        break;
    default:
        break;
    }
}
